package com.card.hwatt.dao.impt;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.card.hwatt.dao.BaseDao;
import com.card.hwatt.dto.PageParam;
import com.card.hwatt.dto.PageResult;

public abstract class BaseDaoImpt<T> implements BaseDao<T> {

	@Autowired
	@Qualifier("sessionFactory")
	protected SessionFactory sessionFactory;

	/**
	 * 获取当前session
	 * @return
	 */
	protected Session getCurrentSession() {
		Session session = sessionFactory.getCurrentSession();
		return session;
	}

	@Override
	public Object uniqueResult(String hql, Object... agrs) {
		Session session = getCurrentSession();
		Query query = session.createQuery(hql);
		if (agrs != null) {
			int i = 0;
			for (Object object : agrs) {
				query.setParameter(i, object);
				i++;
			}
		}

		Object result = query.uniqueResult();
		return result;
	}

	@Override
	public List<T> loadAll() {
		Session session = getCurrentSession();
		Query query = session.createQuery(String.format(" from %s ",
				getEntityClass().getSimpleName()));

		@SuppressWarnings("unchecked")
		List<T> result = query.list();
		return result;
	}

	@Override
	public PageResult<T> loadAll(PageParam param) {
		Session session = getCurrentSession();
		String hql = String.format(" from %s ", getEntityClass()
				.getSimpleName());

		if (StringUtils.isNotEmpty(param.filter)) {
			hql += String.format(" where %s ", param.filter);
		}

		Query totalQuery = session.createQuery("select count(*) " + hql);
		if (CollectionUtils.isNotEmpty(param.params)) {
			int i = 0;
			for (Object object : param.params) {
				totalQuery.setParameter(i, object);
				i++;
			}
		}
		Number total = (Number) totalQuery.uniqueResult();

		if (StringUtils.isNotEmpty(param.sort)) {
			hql += String.format(" order by %s ", param.sort);
		}

		Query query = session.createQuery(hql);

		if (param.rows > 0 && param.page > 0) {
			query = query.setFirstResult(param.rows * (param.page - 1))
					.setMaxResults(param.rows);
		}

		if (CollectionUtils.isNotEmpty(param.params)) {
			int i = 0;
			for (Object object : param.params) {
				query.setParameter(i, object);
				i++;
			}
		}

		@SuppressWarnings("unchecked")
		List<T> list = query.list();
		PageResult<T> result = new PageResult<T>();
		result.rows = list;
		result.total = total.longValue();
		return result;
	}

	@SuppressWarnings("unchecked")
	private Class<T> getEntityClass() {
		Class<?> clz = getClass();

		Type genericType = clz.getGenericSuperclass();

		if (!(genericType instanceof ParameterizedType)) {
			return null;
		}

		ParameterizedType pt = (ParameterizedType) genericType;
		Type[] types = pt.getActualTypeArguments();
		if (types.length < 1) {
			return null;
		}

		Type type = types[0];
		Class<T> entityClass = (Class<T>) type;
		return entityClass;
	}

	@Override
	public T get(Serializable id) {
		Session session = getCurrentSession();
		Object obj = session.get(getEntityClass(), id);
		if (obj == null) {
			return null;
		}

		@SuppressWarnings("unchecked")
		T result = (T) obj;
		return result;
	}

	@Override
	public void save(T entity) {
		Session session = getCurrentSession();
		session.save(entity);
	}

	@Override
	public void update(T entity) {
		Session session = getCurrentSession();
		session.update(entity);
	}

	@Override
	public void delete(Serializable id) {
		Session session = getCurrentSession();
		Object obj = session.get(getEntityClass(), id);
		if (obj == null) {
			return;
		}

		@SuppressWarnings("unchecked")
		T entity = (T) obj;
		session.delete(entity);
	}
}
